﻿/************************************************************************************
 * xujiajun@yoozoo.com 御剑
 * 继承了层级抽象类的基于格子划分的地块层级
 ***********************************************************************************/

using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using WorldMapBase.Tile;
using Yoozoo.Managers;

namespace WorldMapBase.Layer
{
    /// <summary>
    /// 继承了层级抽象类的基于格子划分的地块层级
    /// </summary>
    public class TileLayer : Layer
    {
        /// <summary>
        /// 测试标记开关，打开后会输出部分计算日志
        /// </summary>
        public bool debug = false;

        /// <summary>
        /// 每个格子的尺寸
        /// </summary>
        private int m_TileSize;

        /// <summary>
        /// 每个格子一半的尺寸
        /// </summary>
        private int m_HalfTileSize;

        /// <summary>
        /// 层级范围
        /// </summary>
        private int4 m_LayerRect;

        /// <summary>
        /// 地块层级监听者
        /// </summary>
        private ITileLayerListener m_Listener;

        /// <summary>
        /// 上一帧视图左下角所在的格子坐标
        /// </summary>
        private int2 m_LastLBTileXY;

        /// <summary>
        /// 上一帧视图右上角所在的格子坐标
        /// </summary>
        private int2 m_LastRTTileXY;

        /// <summary>
        /// 每一行的格子数量
        /// </summary>
        private int m_LayerRol;

        /// <summary>
        /// 层级范围内最小左下格子
        /// </summary>
        private int2 m_MinXY;

        /// <summary>
        /// 层级范围内最大右上格子
        /// </summary>
        private int2 m_MaxXY;

        /// <summary>
        /// 第一次时比较特殊，只有添加没有移除，使用一个标记来记录
        /// </summary>
        private bool b_FirstRuntime;

        /// <summary>
        /// 构造地块层级
        /// </summary>
        /// <param name="tileSize">格子尺寸</param>
        /// <param name="layerRect">层级范围（xy：左下世界坐标，zw：长宽）</param>
        public TileLayer(int tileSize, int4 layerRect)
        {
            m_TileSize = tileSize;
            m_LayerRect = layerRect;
            m_HalfTileSize = m_TileSize >> 1;

            m_MinXY = new int2 { x = layerRect.x / m_TileSize, y = layerRect.y / m_TileSize };
            m_MaxXY = new int2 { x = (layerRect.z - 1) / m_TileSize, y = (layerRect.w - 1) / m_TileSize };

            m_LayerRol = m_MaxXY.x + 1;
        }

        /// <summary>
        /// 构造地块层级
        /// </summary>
        /// <param name="tileSize">格子尺寸</param>
        /// <param name="layerRect">层级范围（xy：左下世界坐标，zw：长宽）</param>
        /// <param name="listener">地块层级的监听者</param>
        public TileLayer(int tileSize, int4 layerRect, ITileLayerListener listener) : this(tileSize, layerRect)
        {
            SetListener(listener);
        }

        /// <summary>
        /// 设置地块层级的监听者
        /// </summary>
        /// <param name="listener">监听者</param>
        public void SetListener(ITileLayerListener listener)
        {
            m_Listener = listener;
        }

        public void GetTileGridRange(int4 viewRect, out int2 lbTileXY, out int2 rtTileXY)
        {
            if (viewRect.x < 0 || viewRect.y < 0)
            {
                // 视野看到负坐标
                lbTileXY = viewRect.xy / m_TileSize;
                if (viewRect.x < 0)
                {
                    lbTileXY.x = lbTileXY.x  - 1;
                }
                if (viewRect.y < 0)
                {
                    lbTileXY.y = lbTileXY.y - 1;
                }
                lbTileXY = math.clamp(lbTileXY, m_MinXY, m_MaxXY);

                rtTileXY = (viewRect.xy + viewRect.zw);
                if (rtTileXY.x < 0)
                {
                    rtTileXY.x = rtTileXY.x / m_TileSize - 1;
                }
                else
                {
                    rtTileXY.x = rtTileXY.x / m_TileSize;
                }
                if (rtTileXY.y < 0)
                {
                    rtTileXY.y = rtTileXY.y / m_TileSize - 1;
                }
                else
                {
                    rtTileXY.y = rtTileXY.y / m_TileSize;
                }
                rtTileXY = math.clamp(rtTileXY, m_MinXY, m_MaxXY);
            }
            else
            {
                lbTileXY = math.clamp((viewRect.xy ) / m_TileSize, m_MinXY, m_MaxXY); // 现在要以0点为计算 极值为m_LayerRect.xy
                rtTileXY = math.clamp((viewRect.xy + viewRect.zw ) / m_TileSize, m_MinXY, m_MaxXY);
            }
      
        }

        public void SetLastViewRect(int4 viewRect)
        {
            GetTileGridRange(viewRect, out m_LastLBTileXY, out m_LastRTTileXY);
        }
        
        protected override void OnCreate()
        {
            b_FirstRuntime = true;
            m_LastLBTileXY = m_LastRTTileXY = new int2(-1, -1);
        }

        protected override void OnDestroy()
        {
            RemoveTiles(m_LastLBTileXY.x, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);

            if (DynamicLayerMgr.worldEntry.GetLODLevel() > 2)
            {
                RemoveAdorn(m_LastLBTileXY.x, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);
            }
        }

        public void UpdateViewForce(int4 viewRect)
        {
            if (IsCreated())
            {
                OnUpdateViewRect(viewRect);
            }
        }
        
        protected override void OnUpdateViewRect(int4 viewRect)
        {
            if (!IsCreated())
            {
                return;
            }
            // 获取新视图的左下和右上的格子坐标
            int2 lbTileXY = new int2();
            int2 rtTileXY = new int2();
            GetTileGridRange(viewRect, out lbTileXY, out rtTileXY);

            // 计算格子坐标是否和上一帧相比产生了变化
            var lbResult = m_LastLBTileXY == lbTileXY;
            var rtResult = m_LastRTTileXY == rtTileXY;

            if (debug)
            {
                Debug.LogError(string.Format("********层级{0}*********", id));
                Debug.LogError(string.Format("一行{0}个格子", m_LayerRol));
                Debug.LogError(string.Format("视图：左下({0}, {1})，长宽({2}, {3})", viewRect.x, viewRect.y, viewRect.z, viewRect.w));
                Debug.LogError(string.Format("旧格子：左下({0}, {1})，右上({2}, {3})", m_LastLBTileXY.x, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y));
                Debug.LogError(string.Format("新格子：左下({0}, {1})，右上({2}, {3})", lbTileXY.x, lbTileXY.y, rtTileXY.x, rtTileXY.y));
            }

            if (b_FirstRuntime)
            {
                AddTiles(lbTileXY.x, lbTileXY.y, rtTileXY.x, rtTileXY.y);
                b_FirstRuntime = false;
            }
            else if (!lbResult.x || !lbResult.y || !rtResult.x || !rtResult.y)
            {
                // 没有相交
                if (lbTileXY.x > m_LastRTTileXY.x || rtTileXY.x < m_LastLBTileXY.x || lbTileXY.y > m_LastRTTileXY.y || rtTileXY.y < m_LastLBTileXY.y)
                {
                    RemoveTiles(m_LastLBTileXY.x, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);
                    RemoveAdorn(m_LastLBTileXY.x, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);
                    AddTiles(lbTileXY.x, lbTileXY.y, rtTileXY.x, rtTileXY.y);
                }
                // 有相交
                else
                {
                    //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                    //sw.Start();

                    // 先移除原视图中当前未相交的部分
                    if (m_LastLBTileXY.x < lbTileXY.x)
                    {
                        // 移除左边
                        RemoveTiles(m_LastLBTileXY.x, m_LastLBTileXY.y, lbTileXY.x - 1, m_LastRTTileXY.y);
                        RemoveAdorn(m_LastLBTileXY.x, m_LastLBTileXY.y, lbTileXY.x - 1, m_LastRTTileXY.y);
                    }
                    if (m_LastRTTileXY.x > rtTileXY.x)
                    {
                        // 移除右边
                        RemoveTiles(rtTileXY.x + 1, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);
                        RemoveAdorn(rtTileXY.x + 1, m_LastLBTileXY.y, m_LastRTTileXY.x, m_LastRTTileXY.y);
                    }
                    if (m_LastRTTileXY.y > rtTileXY.y)
                    {
                        // 移除上边
                        RemoveTiles(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), rtTileXY.y + 1, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), m_LastRTTileXY.y);
                        RemoveAdorn(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), rtTileXY.y + 1, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), m_LastRTTileXY.y);
                    }
                    if (m_LastLBTileXY.y < lbTileXY.y)
                    {
                        // 移除下边
                        RemoveTiles(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), m_LastLBTileXY.y, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), lbTileXY.y - 1);
                        RemoveAdorn(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), m_LastLBTileXY.y, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), lbTileXY.y - 1);
                    }

                    // 添加视图中新加的部分
                    if (m_LastLBTileXY.x > lbTileXY.x)
                    {
                        // 添加左边
                        AddTiles(lbTileXY.x, lbTileXY.y, m_LastLBTileXY.x - 1, rtTileXY.y);
                    }
                    if (m_LastRTTileXY.x < rtTileXY.x)
                    {
                        // 添加右边
                        AddTiles(m_LastRTTileXY.x + 1, lbTileXY.y, rtTileXY.x, rtTileXY.y);
                    }
                    if (m_LastRTTileXY.y < rtTileXY.y)
                    {
                        // 添加上边
                        AddTiles(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), m_LastRTTileXY.y + 1, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), rtTileXY.y);
                    }
                    if (m_LastLBTileXY.y > lbTileXY.y)
                    {
                        // 添加下边
                        AddTiles(Mathf.Max(lbTileXY.x, m_LastLBTileXY.x), lbTileXY.y, Mathf.Min(rtTileXY.x, m_LastRTTileXY.x), m_LastLBTileXY.y - 1);
                    }


                    //sw.Stop();
                    //Debug.Log(string.Format("layer {0} , time {1}", layerID, sw.ElapsedMilliseconds));
                }
            }
            m_LastLBTileXY = lbTileXY;
            m_LastRTTileXY = rtTileXY;
        }

        /// <summary>
        /// 添加指定区域的Tile
        /// </summary>
        /// <param name="startX"></param>
        /// <param name="endX"></param>
        /// <param name="startY"></param>
        /// <param name="endY"></param>
        private void AddTiles(int startX, int startY, int endX, int endY)
        {
            for (int j = startY; j <= endY; j++)
            {
                var startIndex = j * m_LayerRol;
                for (int i = startX; i <= endX; i++)
                {
                    var worldPos = new int2 { x =i * m_TileSize + m_HalfTileSize, y = j * m_TileSize + m_HalfTileSize };
                    int tileIdx = startIndex + i;
                    if (!WorldMapConfigData.CheckTileInWorld(i, j, m_TileSize))
                    {
                        tileIdx = WorldMapConfigData.GetOverSeaTileIdx(i, j, m_TileSize);
                    }
                    //if (debug)
                    //{
                    //    Debug.Log(string.Format("添加格子({0}, {1})，序号为{2}", i, j, tileIdx));
                    //}

                    TileDisplayManager.Instance.AddShowCommand(layerID,id, tileIdx, worldPos);
                }
            }

            if (layerID == WorldEntry.PLANE_LAYER_ID && id <= 2) // 这里需要判断层级 <= 2 不然会堵塞队列
            {
                if (DynamicLayerMgr.worldEntry._mapPointAdornSystem)
                {
                    DynamicLayerMgr.worldEntry._mapPointAdornSystem.AddShowTileIdx(startX, startY, endX, endY);
                }
            }
        }

        
        private static List<int> cacheTiles = new List<int>(200);
        /// <summary>
        /// 移除指定区域的Tile
        /// </summary>
        /// <param name="startX"></param>
        /// <param name="endX"></param>
        /// <param name="startY"></param>
        /// <param name="endY"></param>
        private void RemoveTiles(int startX, int startY, int endX, int endY)
        {
            var len = (endY - startY+1) * (endX - startX+1)+1;
            for (int j = startY; j <= endY; j++)
            {
                var startIndex = j * m_LayerRol;
                for (int i = startX; i <= endX; i++)
                {
                    int tileIdx = startIndex + i;
                    if (!WorldMapConfigData.CheckTileInWorld(i, j, m_TileSize))
                    {
                        tileIdx = WorldMapConfigData.GetOverSeaTileIdx(i, j, m_TileSize);
                    }
                    //Debug.LogError(string.Format("移除格子({0}, {1})，序号为{2}", i, j, tileIdx));
                    cacheTiles.Add(tileIdx);
                }
            }
            // TileHideCommand
            for (int i = 0; i < cacheTiles.Count; i++)
            {
                TileDisplayManager.Instance.AddHideCommand(layerID,id,cacheTiles[i]);
            }
            cacheTiles.Clear();
        }

        private void RemoveAdorn(int startX, int startY, int endX, int endY)
        {
            if (layerID == WorldEntry.PLANE_LAYER_ID && id <= 2)
            {
                if (DynamicLayerMgr.worldEntry._mapPointAdornSystem)
                {
                    DynamicLayerMgr.worldEntry._mapPointAdornSystem.RemoveShowTileIdx(startX, startY, endX, endY);
                }
            }
        }
    }
}
